package com.dayu.finecomm.dsc.protocol;

/**
 * H7710S-DDP协议
 * @author hddz
 * @since 2017-07-27 09:03:45
 * @version V1.0
 */
public class DDP {
	/**
	 * DDP报文使用的传输类型
	 */
	public static final int DDP_TCP = 1;	// TCP报文
	public static final int DDP_UDP = 2;	// UDP报文
	
	/**
	 * DDP包的起始/结束标志
	 */
	public static final byte DDP_START_END_SIGN = 0x7B;
	
	/**
	 * 数据包各字段长度
	 */
	public static final int DDP_START_SIGN_LENGTH = 1;		// 起始标志长度
	public static final int DDP_PACK_TYPE_LENGTH = 1;		// 包类型
	public static final int DDP_PACK_LEN_LENGTH = 2;		// 包长度
	public static final int DDP_DTU_IDENTY_LENGTH = 11;		// DTU身份识别
	public static final int DDP_END_SIGN_LENGTH = 1;		// 结束标志
	
	/**
	 * DDP协议包最小长度
	 */
	public static final int DDP_PACK_MIN_LENGTH = DDP_START_SIGN_LENGTH +
			                                      DDP_PACK_TYPE_LENGTH +
			                                      DDP_PACK_LEN_LENGTH + 
			                                      DDP_DTU_IDENTY_LENGTH +
			                                      DDP_END_SIGN_LENGTH;
	
	/**
	 * 用户数据最大长度
	 */
	public static final int DDP_USER_DATA_MAX_LENGTH = 1024;
	
	/**
	 * DTC发送的协议包类型
	 */
	public static final byte DTU_PACK_TYPE_REG = 0x01;			// 终端请求注册
	public static final byte DTU_PACK_TYPE_UNREG = 0x02;		// 终端请求注销
	public static final byte DTU_PACK_TYPE_INVALID = 0x04;		// 无效命令或协议包
	public static final byte DTU_PACK_TYPE_RECV_ACK = 0x05;		// 接收到DSC用户数据的应答包
	public static final byte DTU_PACK_TYPE_SEND_DATA = 0x09;	// 发送给DSC的用户数据包
	public static final byte DTU_PACK_TYPE_QUERY_ACK = 0x0B;	// 查询DTU参数的应答包
	public static final byte DTU_PACK_TYPE_SETTING_ACK = 0x0D;	// 设置DTU参数的应打包
	public static final byte DTU_PACK_TYPE_LOG_ACK = 0x0E;		// 提取DTU日志应答包
	public static final byte DTU_PACK_TYPE_UPGRADE_ACK = 0x0F;	// 远程升级的回应包
	
	/**
	 * DSC端发送的协议包
	 */
	public static final byte DSC_PACK_TYPE_REG_SUCCESS = (byte)0x81;	// 注册成功
	public static final byte DSC_PACK_TYPE_UNREG_SUCCESS = (byte)0x82;	// 注销成功
	public static final byte DSC_PACK_TYPE_RE_REG = (byte)0x83;			// DSC要求DTU向DSC重注册
	public static final byte DSC_PACK_TYPE_INVALID = (byte)0x84;		// 无效命令或协议包
	public static final byte DSC_PACK_TYPE_RECV_ACK = (byte)0x85;		// 接收到DTU用户数据应答包
	public static final byte DSC_PACK_TYPE_SEND_DATA = (byte)0x89;		// 发送给DTU用户数据
	public static final byte DSC_PACK_TYPE_QUERY_ARG = (byte)0x8B;		// 查询DTU参数
	public static final byte DSC_PACK_TYPE_SETTING_ARG = (byte)0x8D;	// 设置DTU参数
	public static final byte DSC_PACK_TYPE_GET_LOG = (byte)0x8E;		// 提取DTU日志
	public static final byte DSC_PACK_TYPE_UPGRADE = (byte)0x8F;		// DSC通知DTU远程升级的数据包
	public static final byte DSC_PACK_TYPE_AWAKE_DTU = 0x13;	// 通过远程唤醒DTU，不需要应打包
	public static final byte DSC_PACK_TYPE_START_DDP = 0x14;	// 短信通知启动DDP管理通道，不需要应打包
	
	/**
	 * DDP包基本字段，基类
	 * @author hddz
	 * @since 2017-07-27 10:06:12
	 * @version V1.0
	 */
	public class DDPPack {
		/**
		 * 包类型
		 */
		private byte mPackType = 0x00;
		
		/**
		 * 包长度
		 */
		private short mPackLen = 0x00;
		
		/**
		 * DTU身份识别
		 */
		private byte[] mIdenty = null;
		
		DDPPack(byte type, short len, byte[] identy) {
			mPackType = (byte)(0xFF & type);
			mPackLen = len;
			mIdenty = new byte[DDP_DTU_IDENTY_LENGTH];
			System.arraycopy(identy, 0, mIdenty, 0, DDP_DTU_IDENTY_LENGTH);
		}
		
		/**
		 * 获取包类型
		 * @return
		 */
		public byte getType() {
			return mPackType;
		}
		
		/**
		 * 获取包长度
		 * @return
		 */
		public short getLen() {
			return mPackLen;
		}
		
		/**
		 * 获取DTU身份识别
		 * @return
		 */
		public byte[] getIdenty() {
			return mIdenty;
		}
	}
	
	///////////// 以下为DTU->DSC 协议包 ///////////////////////////
	
	/**
	 * 注册包，终端注册(DTU->DSC)
	 * @author hddz
	 * @since 2017-07-27 10:06:12
	 * @version V1.0
	 */
	public class DTUReg extends DDPPack {
		/**
		 * DTU本地移动IP
		 */
		private int mIp;
		
		/**
		 * DTU本地移动端口
		 */
		private short mPort;
		
		public DTUReg(byte[] identy, int ip, short port) {
			super(DTU_PACK_TYPE_REG, (short)(DDP_PACK_MIN_LENGTH+4+2), identy);
			
			mIp = ip;
			mPort = port;
		}
		
		/**
		 * 获取DTU本地移动IP
		 * @return
		 */
		public int getIp() {
			return mIp;
		}
		
		/**
		 * 获取DTU本地移动端口
		 * @return
		 */
		public short getPort() {
			return mPort;
		}
	}
	
	/**
	 * 终端注销(DTU->DSC)
	 * @author hddz
	 * @since 2017-07-27 10:06:12
	 * @version V1.0
	 */
	public class DTUUnreg extends DDPPack {
		public DTUUnreg(byte[] identy) {
			super(DTU_PACK_TYPE_UNREG, (short)(DDP_PACK_MIN_LENGTH), identy);
		}
	}
	
	/**
	 * DTU发送给DSC的数据包 (DTU->DSC)
	 * @author hddz
	 * @since 2017-07-27 10:06:12
	 * @version V1.0
	 */
	public class DTUSendData extends DDPPack {
		/**
		 * DSC发送给DTU的用户数据
		 */
		private byte[] mData = null;
		
		public DTUSendData(byte[] identy, byte[] data) {
			super(DTU_PACK_TYPE_SEND_DATA, (short)(DDP_PACK_MIN_LENGTH+data.length), identy);
			
			mData = new byte[data.length];
			System.arraycopy(data, 0, mData, 0, data.length);
		}
		
		/**
		 * 返回DSC发送给DTU的用户数据
		 * @return
		 */
		public byte[] getData() {
			return mData;
		}
	}
	
	/**
	 * DTU应答收到正确的数据包(DTU->DSC)
	 * @author hddz
	 * @since 2017-07-27 10:06:12
	 * @version V1.0
	 */
	public class DTURecvAck extends DDPPack {
		public DTURecvAck(byte[] identy) {
			super(DTU_PACK_TYPE_RECV_ACK, (short)(DDP_PACK_MIN_LENGTH), identy);
		}
	}
	
	/**
	 * 无效命令或数据(DTU->DSC)
	 * @author hddz
	 * @since 2017-07-27 10:06:12
	 * @version V1.0
	 */
	public class DTUInvalid extends DDPPack {
		public DTUInvalid(byte[] identy) {
			super(DTU_PACK_TYPE_INVALID, (short)(DDP_PACK_MIN_LENGTH), identy);
		}
	}
	
	///////////// 以下为DSC->DTU 协议包 ///////////////////////////
	
	/**
	 * 注册应答，注册成功(DSC->DTU)
	 * @author hddz
	 * @since 2017-07-27 10:06:12
	 * @version V1.0
	 */
	public class DSCRegAck extends DDPPack {
		public DSCRegAck(byte[] identy) {
			super(DSC_PACK_TYPE_REG_SUCCESS, (short)(DDP_PACK_MIN_LENGTH), identy);
		}
	}
	
	/**
	 * 注销应答，注销成功(DSC->DTU)
	 * @author hddz
	 * @since 2017-07-27 10:06:12
	 * @version V1.0
	 */
	public class DSCUnregAck extends DDPPack {
		public DSCUnregAck(byte[] identy) {
			super(DSC_PACK_TYPE_UNREG_SUCCESS, (short)(DDP_PACK_MIN_LENGTH), identy);
		}
	}
	
	/**
	 * DSC要求DTU向DSC重注册(DSC->DTU)
	 * @author hddz
	 * @since 2017-07-27 10:06:12
	 * @version V1.0
	 */
	public class DSCRereg extends DDPPack {
		public DSCRereg(byte[] identy) {
			super(DSC_PACK_TYPE_RE_REG, (short)(DDP_PACK_MIN_LENGTH), identy);
		}
	}
	
	/**
	 * 无效命令或数据(DSC->DTU)
	 * @author hddz
	 * @since 2017-07-27 10:06:12
	 * @version V1.0
	 */
	public class DSCInvalid extends DDPPack {
		public DSCInvalid(byte[] identy) {
			super(DSC_PACK_TYPE_INVALID, (short)(DDP_PACK_MIN_LENGTH), identy);
		}
	}
	
	/**
	 * DSC应答收到正确的数据包(DSC->DTU)
	 * @author hddz
	 * @since 2017-07-27 10:06:12
	 * @version V1.0
	 */
	public class DSCRecvAck extends DDPPack {
		public DSCRecvAck(byte[] identy) {
			super(DSC_PACK_TYPE_RECV_ACK, (short)(DDP_PACK_MIN_LENGTH), identy);
		}
	}
	
	/**
	 * DSC发送给DTU的数据包 (DSC->DTU)
	 * @author hddz
	 * @since 2017-07-27 10:06:12
	 * @version V1.0
	 */
	public class DSCSendData extends DDPPack {
		/**
		 * DSC发送给DTU的用户数据
		 */
		private byte[] mData = null;
		
		public DSCSendData(byte[] identy, byte[] data) {
			super(DSC_PACK_TYPE_SEND_DATA, (short)(DDP_PACK_MIN_LENGTH+data.length), identy);
			
			mData = new byte[data.length];
			System.arraycopy(data, 0, mData, 0, data.length);
		}
		
		/**
		 * 返回DSC发送给DTU的用户数据
		 * @return
		 */
		public byte[] getData() {
			return mData;
		}
	}
	
	/**
	 * 解析DDP协议包
	 * @param data 协议包流数据raw data
	 * @return DDPPack
	 */
	public DDPPack unpack(byte[] data) {
		DDPPack ddp = null;
		int nIndex = 0;
		
		if (DDP_PACK_MIN_LENGTH <= data.length) {
			if (DDP_START_END_SIGN == data[nIndex]) {
				nIndex += DDP_START_SIGN_LENGTH;
				
				// 包类型
				byte type = data[nIndex];
				nIndex += DDP_PACK_TYPE_LENGTH;
				
				// 包长度
				short length = (short)(((short)(0xFF & data[nIndex]) << 8) | 
						               ((short)(0xFF & data[nIndex+1])));
				nIndex += DDP_PACK_LEN_LENGTH;
				
				if (DDP_START_END_SIGN == data[length-1]) {
					// DTU身份识别码
					byte[] identy = new byte[DDP_DTU_IDENTY_LENGTH];
					System.arraycopy(data, nIndex, identy, 0, DDP_DTU_IDENTY_LENGTH);
					nIndex += DDP_DTU_IDENTY_LENGTH;
					
					switch (type) {
					case DTU_PACK_TYPE_REG:	// 注册包
						int ip = (int)(((int)(0xFF & data[nIndex]) << 24) |
						               ((int)(0xFF & data[nIndex+1]) << 16) |
						               ((int)(0xFF & data[nIndex+2]) << 8) |
						               ((int)(0xFF & data[nIndex+3])));
						nIndex += 4;
						
						short port = (short)(((short)(0xFF & data[nIndex]) << 8) | 
					                         ((short)(0xFF & data[nIndex+1])));
						nIndex += 2;
						
						ddp = new DTUReg(identy, ip, port);
						break;
					case DTU_PACK_TYPE_UNREG:	// 注销包
						ddp = new DTUUnreg(identy);
						break;
					case DTU_PACK_TYPE_INVALID: // 无效命令或数据
						ddp = new DTUInvalid(identy);
						break;
					case DTU_PACK_TYPE_RECV_ACK: // DTU应答收到正确数据包
						ddp = new DTURecvAck(identy);
						break;	
					case DTU_PACK_TYPE_SEND_DATA: // DTU发送给DSC数据包
						byte[] user = null;
						if (DDP_PACK_MIN_LENGTH == length) { // UDP Send User Data
							user = new byte[data.length-length];
							System.arraycopy(data, length, user, 0, (data.length-length));
						} else { // TCP Send User Data
							user = new byte[length-DDP_PACK_MIN_LENGTH];
							System.arraycopy(data, nIndex, user, 0, length-DDP_PACK_MIN_LENGTH);
						}
						ddp = new DTUSendData(identy, user);
						break;
					default:
						break;
					}
				}
			}
		}
		
		return ddp;
	}
	
	/**
	 * 打包DDP协议包
	 * @param ddp DDPPack
	 * @param nNet 网络传输方式: 1 - TCP, 2 - UDP
	 * @return raw data
	 */
	public byte[] pack(DDPPack ddp, int nNet) {
		byte[] data = null;
		int nIndex = 0;
		short nLen = 0;
		
		if (null != ddp) {
			nLen = ddp.getLen();
			data = new byte[nLen];
			
			// 起始标志
			data[nIndex] = DDP_START_END_SIGN;
			nIndex += DDP_START_SIGN_LENGTH;
			// 包类型
			data[nIndex] = ddp.getType();
			nIndex += DDP_PACK_TYPE_LENGTH;
			// 包长度
			if (DDP_UDP == nNet && DSC_PACK_TYPE_SEND_DATA == ddp.getType()) {
				data[nIndex] = (byte)(0xFF & (DDP_PACK_MIN_LENGTH >> 8));
				data[nIndex+1] = (byte)(0xFF & DDP_PACK_MIN_LENGTH);
			} else {
				data[nIndex] = (byte)(0xFF & (nLen >> 8));
				data[nIndex+1] = (byte)(0xFF & nLen);
			}
			nIndex += DDP_PACK_LEN_LENGTH;
			// DTU身份识别码
			System.arraycopy(ddp.getIdenty(), 0, data, nIndex, DDP_DTU_IDENTY_LENGTH);
			nIndex += DDP_DTU_IDENTY_LENGTH;
			
			// TCP传输模式用户数据
			if (DDP_TCP == nNet && DSC_PACK_TYPE_SEND_DATA == ddp.getType()) {
				DSCSendData ddpData = (DSCSendData)ddp;
				System.arraycopy(ddpData.getData(), 0, data, nIndex, ddpData.getData().length);
				nIndex += ddpData.getData().length;
			}
			
			// 结束标志
			data[nIndex] = DDP_START_END_SIGN;
			nIndex += DDP_START_SIGN_LENGTH;
			
			// UDP传输模式用户数据
			if (DDP_UDP == nNet && DSC_PACK_TYPE_SEND_DATA == ddp.getType()) {
				DSCSendData ddpData = (DSCSendData)ddp;
				System.arraycopy(ddpData.getData(), 0, data, nIndex, ddpData.getData().length);
				nIndex += ddpData.getData().length;
			}
		}
		
		return data;
	}
	
	/**
	 * 生成初始化的DTU身份识别码
	 * @return
	 */
	public static byte[] getDefaultIdenty() {
		byte[] identy = new byte[DDP_DTU_IDENTY_LENGTH];
		
		return identy;
	}
}
